/**
 * 所有版权归 广西梧州 陈锦韬 所有
 *
 * @Title: RxRegister
 * @Package com.rx.core.base
 * @Description: 自定义注册
 * @author: 陈锦韬
 * @date: 2021\6\11 0011
 * @version V1.0
 * @Copyright: 2021 陈锦韬  All rights reserved.
 */
package com.rx.core.base;

import com.baomidou.mybatisplus.annotation.TableField;
import com.rx.core.anno.RxAlias;
import com.rx.core.dbase.RxBaseDbMust;
import com.rx.core.enm.RX_LOG_MODE;
import com.rx.core.util.EmptyChecker;
import com.rx.core.util.RxUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.util.Assert;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author: Administrator
 * @Description: 自定义注册
 * @date: 2021\6\11 0011
 */
@Slf4j
abstract public class RxScanner extends ClassPathBeanDefinitionScanner {
    public static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    public static Map<String,Class> urlFormClassMap = new HashMap<>();
    public static Map<String, List<Field>> urlFormFieldMap = new HashMap<>();
    public static Map<String, String> urlFormAliasMap = new HashMap<>();

    public RxScanner(BeanDefinitionRegistry registry) {
        super(registry,false);
    }

    protected void register(Class<?> loadClass,BeanDefinition candidate){
        urlFormClassMap.put(loadClass.getSimpleName(),loadClass);
        RxAlias rxAlias = loadClass.getAnnotation(RxAlias.class);
        if (EmptyChecker.notEmpty(rxAlias)){
            urlFormAliasMap.put(rxAlias.value(),loadClass.getSimpleName());
        }

        List<Field> columnList = RxUtil.Reflection.getAllField(loadClass, TableField.class,true);
        try {
            Field bidField = RxBaseDbMust.class.getDeclaredField(RxBaseDbMust.BID);
            columnList.add(bidField);
        } catch (NoSuchFieldException e) {
            log.error(RX_LOG_MODE.ERROR.getFormat("获取BID字段错误"));
        }
        urlFormFieldMap.put(loadClass.getSimpleName(),columnList);
        log.info(RX_LOG_MODE.REG_DATA.getFormat(),candidate.getBeanClassName());
    }
    protected Set<BeanDefinition> scanCandidate(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN;
            Resource[] resources = ((ResourcePatternResolver)super.getResourceLoader()).getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                }
                else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

    protected void scanRxData(String[] basePackages,Class filterAnno){
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = scanCandidate(basePackage);
            for (BeanDefinition candidate : candidates) {
                try {
                    Class<?> loadClass = this.getClass().getClassLoader().loadClass(candidate.getBeanClassName());
                    if(EmptyChecker.notEmpty(loadClass.getAnnotation(filterAnno))){
                        register(loadClass,candidate);
                    }
                } catch (ClassNotFoundException e) {
                    log.error(RX_LOG_MODE.ERROR.getFormat("RxData类加载失败"));
                }
            }
        }
    }

    public static Class<?> getClassByName(String name){
        Class cls = urlFormClassMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name));
        if (EmptyChecker.isEmpty(cls)){
            cls = urlFormClassMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name + "-" + RxBaseConstant.INPUT_DATA_CLASS_SUFFIX));
        }
        if (EmptyChecker.isEmpty(cls)){
            // 别名
            cls = urlFormClassMap.get(urlFormAliasMap.get(name));
        }
        return cls;
    }

    public static List<Field> getFieldByName(String name){
        List<Field> list = urlFormFieldMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name));
        if (EmptyChecker.isEmpty(list)){
            list = urlFormFieldMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name + "-" + RxBaseConstant.INPUT_DATA_CLASS_SUFFIX));
        }
        if (EmptyChecker.isEmpty(list)){
            // 别名
            list = urlFormFieldMap.get(urlFormAliasMap.get(name));
        }
        return list;
    }

    public static String getTableName(String name){
        Class cls = urlFormClassMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name));
        if (EmptyChecker.isEmpty(cls)){
            cls = urlFormClassMap.get(RxUtil.StringUtil.dashToFirstUpperHump(name + "-" + RxBaseConstant.INPUT_DATA_CLASS_SUFFIX));
        }
        if (EmptyChecker.isEmpty(cls)){
            // 别名
            cls = urlFormClassMap.get(urlFormAliasMap.get(name));
            String className = cls.getSimpleName();
            if (className.endsWith(RxBaseConstant.INPUT_DATA_CLASS_SUFFIX)){
                className = className.substring(0,className.length()-RxBaseConstant.INPUT_DATA_CLASS_SUFFIX.length());
            }
            return RxUtil.StringUtil.firstUpperHumpToLine(className);
        }else {
            return RxUtil.StringUtil.dashToLine(name);
        }
    }
}
